package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import sun.misc.Cleaner;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author atguigu-mqx
 */
@Service
public class CartServiceImpl implements CartService {

    //  如果数据存储有mysql 的话，则这里需要引入mapper，但是，现在只需要使用redis即可！
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Override
    public void addToCart(Long skuId, String userId, Long skuNum) {
        /*
        1.  先判断当前购物车中是否有该商品！
            true：
                有这个商品，数量相加  更新数据
            false:
                直接插入数据
         */
        //  分析使用哪个数据类型，以及key hash 结构： hset key field value  key=user:userId:cart field = skuId  value = cartInfo;
        //  hget key field; 获取购物车中的单个购物项    hvals key;  查看购物车列表！
        String cartKey = getCartKey(userId);
        //        Boolean flag = this.redisTemplate.boundHashOps(cartKey).hasKey(skuId.toString());
        //        CartInfo cartInfo = (CartInfo) this.redisTemplate.boundHashOps(cartKey).get(skuId.toString());
        //        if (flag){
        //            //  有这个商品
        //        }else {
        //            //  没有这个商品
        //        }

        //  这个value 是什么? 应该是购物项！
        CartInfo cartInfoExist = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
//        Boolean aBoolean = this.redisTemplate.opsForHash().hasKey(cartKey, skuId.toString());
        //  判断
        if (cartInfoExist!=null){
            //  更新数据
            cartInfoExist.setSkuNum(cartInfoExist.getSkuNum()+skuNum.intValue());
            //  查询一下最新的实时价格
            cartInfoExist.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            //  细节：
            cartInfoExist.setIsChecked(1);
            cartInfoExist.setUpdateTime(new Date());
            //  将这个对象放入缓存！
            //  this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfoExist);

        }else {
            //  插入数据
            CartInfo cartInfo = new CartInfo();
            //  赋值操作
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setSkuPrice(skuInfo.getPrice());
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum.intValue());
            cartInfo.setSkuId(skuId);
            cartInfo.setUserId(userId);
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            //  放入缓存！
            //  this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfo);
            cartInfoExist=cartInfo;
        }
        //  放入缓存！
        this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfoExist);
        //  如果要是有过期时间的话！
        //  setCartKeyExpire(cartKey);
    }

    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        /*
            1.  判断是否登录，根据判断结果查询不同的购物车！
            2.  查询的结果需要排序！
            3.  有可能需要合并！
                    在登录的情况下
                    .	未登录 ---> 登录合并！
                        合并完成之后，需要删除未登录购物车数据！
                     case1: 有userId ,没有userTempId
                     case2: 没有userId ,有userTempId   return noLoginCartInfoList
                     case3: 有userId ,有userTempId
                        登录情况下合并购物车：
                            先判断未登录购物车集合有数据！
                                true: 有数据
                                    合并
                                false: 没有数据
                                    只需要登录购物车数据
                            删除未登录购物车！
         */
        //  声明一个集合来存储未登录数据
        List<CartInfo> noLoginCartInfoList = null;

        //  完成case2 业务逻辑
        //  属于未登录
        if (!StringUtils.isEmpty(userTempId)){
            String cartKey = this.getCartKey(userTempId);
            //  获取登录的购物车集合数据！
            //  noLoginCartInfoList = this.redisTemplate.boundHashOps(cartKey).values();
            noLoginCartInfoList  = this.redisTemplate.opsForHash().values(cartKey);
        }
        //  这个是集合的排序
        if (StringUtils.isEmpty(userId)){
            if (!CollectionUtils.isEmpty(noLoginCartInfoList)){
                noLoginCartInfoList.sort((o1,o2)->{
                    //  按照更新时间：
                    return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
                });
            }
            //  返回未登录数据！
            return noLoginCartInfoList;
        }
        //  ----------------------case 1 and case3 -----------------------
        /*
        demo:
            登录：
                17  1
                18  1

            未登录：
                17  1
                18  1
                19  2

             合并：
                17  2
                18  2
                19  2
         */
        //  属于登录
        List<CartInfo> LoginCartInfoList = null;
        //  先获取到登录购物车的key
        String cartKey = this.getCartKey(userId);
        //  hset key field value;  hget key field;  hvals key ; hmset key field value field value;  hmset key map;
        //  合并思路二：
        BoundHashOperations<String, String, CartInfo>  boundHashOperations = this.redisTemplate.boundHashOps(cartKey);
        //  判断购物车中的field
        //  boundHashOperations.hasKey(skuId.toString);
        if (!CollectionUtils.isEmpty(noLoginCartInfoList)){
            //  循环遍历未登录购物车集合
            noLoginCartInfoList.stream().forEach(cartInfo -> {
                //  在未登录购物车中的skuId 与登录的购物车skuId 相对  skuId = 17 18
                if (boundHashOperations.hasKey(cartInfo.getSkuId().toString())){
                    //  合并业务逻辑 : skuNum + skuNum 更新时间
                    CartInfo loginCartInfo = boundHashOperations.get(cartInfo.getSkuId().toString());
                    loginCartInfo.setSkuNum(loginCartInfo.getSkuNum()+cartInfo.getSkuNum());
                    loginCartInfo.setUpdateTime(new Date());
                    //  最新价格
                    loginCartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));

                    //  选中状态合并！
                    if (cartInfo.getIsChecked().intValue()==1){
//                        if (loginCartInfo.getIsChecked().intValue()==0){
//                            loginCartInfo.setIsChecked(1);
//                        }
                        loginCartInfo.setIsChecked(1);
                    }
                    //  修改缓存的数据：    hset key field value
                    boundHashOperations.put(cartInfo.getSkuId().toString(),loginCartInfo);
                }else {
                    //  直接添加到缓存！    skuId = 19
                    cartInfo.setUserId(userId);
                    cartInfo.setCreateTime(new Date());
                    cartInfo.setUpdateTime(new Date());
                    boundHashOperations.put(cartInfo.getSkuId().toString(),cartInfo);
                }
            });
            //  删除未登录购物车数据！
            this.redisTemplate.delete(this.getCartKey(userTempId));
        }

        //  获取到合并之后的数据：
        LoginCartInfoList = this.redisTemplate.boundHashOps(cartKey).values();
        if (CollectionUtils.isEmpty(LoginCartInfoList)){
            return new ArrayList<>();
        }
        //  设置合并之后的排序结果！
        LoginCartInfoList.sort(((o1, o2) -> {
            return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
        }));

        //  获取登录的购物车集合数据！
        //  合并思路一：
        //        LoginCartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        //        //  如何判断
        //        if (!CollectionUtils.isEmpty(noLoginCartInfoList)){
        //            //  合并购物车； 合并的条件：判断就是根据skuId 是否相等！
        //            //  还有一种情况！ 判断选中状态！
        //            for (CartInfo noLoginCartInfo : noLoginCartInfoList) {
        //                for (CartInfo loginCartInfo : LoginCartInfoList) {
        //                    if (noLoginCartInfo.getSkuId().intValue()==loginCartInfo.getSkuId().intValue()){
        //                        //  合并业务逻辑
        //                    }else {
        //                        //  直接添加
        //                    }
        //                }
        //            }
        //        }

        return LoginCartInfoList;
    }

    @Override
    public void checkCart(String userId, Integer isChecked, Long skuId) {
        //  操作redis！    hget key field value;  hset key field value;
        String cartKey = this.getCartKey(userId);
        //  获取缓存中的数据
        CartInfo cartInfo = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
        //  判断！
        if (cartInfo!=null){
            cartInfo.setIsChecked(isChecked);
            //  再次放入缓存！
            this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfo);
        }
    }

    @Override
    public void deleteCart(Long skuId, String userId) {
        //  获取到购物车key   hdel key field
        String cartKey = this.getCartKey(userId);
        //  直接删除！
        //  Long delete = this.redisTemplate.boundHashOps(cartKey).delete(skuId.toString());
        Boolean res = this.redisTemplate.boundHashOps(cartKey).hasKey(skuId.toString());
        if (res){
            this.redisTemplate.boundHashOps(cartKey).delete(skuId.toString());
        }

    }

    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        //  获取的选中的购物车列表！
        String cartKey = this.getCartKey(userId);
        //  获取到购物车集合数据：
        List<CartInfo>  cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        List<CartInfo> cartInfos = cartInfoList.stream().filter(cartInfo -> {
            //  再次确认一下最新价格
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            return cartInfo.getIsChecked().intValue() == 1;
        }).collect(Collectors.toList());

        //  返回数据
        return cartInfos;
    }

    @Override
    public void delCart(String userId) {
        String cartKey = this.getCartKey(userId);
        //  获取购物车数据：
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        //  循环遍历
        for (CartInfo cartInfo : cartInfoList) {
            if (cartInfo.getIsChecked().intValue()==1){
                this.redisTemplate.opsForHash().delete(cartKey,cartInfo.getSkuId().toString());
            }
        }
    }

    /**
     * 设置购物车的过期时间
     * @param cartKey
     */
    private void setCartKeyExpire(String cartKey) {
        this.redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

    /**
     * 这个方法就是获取购物车key 的！
     * @param userId
     * @return
     */
    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }



}
